/**
 * 
 */
package ch.gje.playios.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;

import ch.gje.playios.server.exception.BadHTTPRequestException;
import ch.gje.playios.server.handler.BadRequestHandler;
import ch.gje.playios.server.handler.HTTPHandler;
import ch.gje.playios.server.handler.InternalServerErrorHandler;
import ch.gje.playios.server.handler.MethodNotAllowedHandler;
import ch.gje.playios.server.handler.WebSocketHandler;

/**
 * Server class Acts as HTTP and as WebSockets server
 * 
 * @author jannis <jannis@gje.ch>
 */
public class Server implements Runnable {

    /**
     * The server socket
     */
    private ServerSocket server;

    /**
     * Starts the Server
     *
     * @param port
     *            port number
     */
    public Server(int port) {
        try {
            server = new ServerSocket(port);
            new Thread(this).start();
            System.out.println("Server listening on Port "
                    + server.getLocalPort());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Accepts clients
     */
    @Override
    public void run() {
        Socket client;
        try {
            client = server.accept();
            new Thread(this).start();
            handleClient(client);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Delegates to query handler
     *
     * @param client
     *            the client
     * @throws IOException
     */
    private void handleClient(Socket client) throws IOException {
        HTTPConnection connection = new HTTPConnection(client);
        try {
            byte[] request = new byte[1000];
            connection.read(request);
            connection.setRequest(request);

            Map<String, String> headers = connection.getHeaders();
            String requestMethod = headers.get(HTTPConnection.REQUEST_METHOD);
            if (!requestMethod.equals("GET") && !requestMethod.equals("HEAD")) {
                new MethodNotAllowedHandler(connection);
            } else if (headers.containsKey("Upgrade")
                    && headers.get("Upgrade").equals("WebSocket")) {
                new WebSocketHandler(connection);
            } else {
                new HTTPHandler(connection);
            }
        } catch (BadHTTPRequestException e) {
            new BadRequestHandler(connection);
        } catch (Exception e) {
            e.printStackTrace();
            new InternalServerErrorHandler(connection);
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        int port = 8080;
        new Server(port);
    }
}
